<?php
/**************************************************************************************************
	$Id: admin.php,v 1.9 2002/07/11 13:15:10 bboy Exp $
	Functional and useful example of a web-based DNS administration interface.
**************************************************************************************************/

$dbhost = "localhost";
$dbuser = "username";
$dbpass = "password";
$dbname = "mydns";

$ttl_min = 300;
$refresh_min = 300;
$retry_min = 300;
$expire_min = 86400;


/* A few convenience functions */
function esc($str) { return mysql_escape_string($str); }
function nf($n) { return number_format($n); }
function S($n) { return ($n == 1 ? "" : "s"); }

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	OPEN_PAGE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function open_page($title = "MyDNS")
{
	global $PHP_SELF, $query;
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML lang="en">
<HEAD>
	<META http-equiv="Content-Type" content="text/html; charset=US-ASCII">
	<TITLE><?=$title?><?php if (strlen($query)) echo ": $query"; ?></TITLE>
	<STYLE type="text/css">
	<!--
		A { color: blue; text-decoration: none; }
		A:hover { color: red; text-decoration: underline; }

		BODY {
			background: #FFFFEE;
			color: #663300;
			margin: 1% 10% 3% 10%;
		}

		TABLE {
			background: #FFFFCC;
			padding: 10px;
			font-family: monospace;
		}

		TABLE.header {
			width: 100%;
			background: #FFFFEE;
			border-bottom: #663300 solid 2px;
		}

		TABLE.rr {
			width: 100%;
		}

		TABLE.notice {
			padding: 10px;
			font-family: sans-serif;
			font-weight: bold;
			text-align: center;
		}

		H1 {
			font-family: sans-serif;
			font-weight: bold;
			font-size: 300%;
		}

		CAPTION {
			background: #FFFFCC;
			padding: 6px;
			border-bottom: #663300 solid 1px;
			font-family: sans-serif;
			font-size: 150%;
			font-weight: bold;
			text-align: left;
		}

		TD { padding: 3px 5px 3px 5px; }
		TD.leftindent { padding: 3px 10px 3px 100px; }

		TD.rrinsert { border-top: #FFFFCC solid 20px; }
	-->
	</STYLE>
</HEAD>
<BODY>
<!-- Page header -->
<FORM action="<?=$PHP_SELF?>" method=GET>
<TABLE class=header>
	<TR>
		<TD align=left valign=bottom>
			<INPUT type=TEXT name=query value="<?=$query?>" size=25 maxlength=255
			 title="input a domain name to edit records">
		</TD>
		<TD align=right valign=bottom>
<?
	if (file_exists("graphics/mydns-logo.png"))
		echo "<IMG src=\"graphics/mydns-logo.png\" alt=\"MyDNS\">";
	else if (file_exists("mydns-logo.png"))
		echo "<IMG src=\"mydns-logo.png\" alt=\"MyDNS\">";
	else
		echo "<H1>MyDNS</H1>";
?>
		</TD>
	</TR>
</TABLE>
</FORM>
<?php
}
/*--- open_page() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	CLOSE_PAGE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function close_page()
{
?>
</BODY>
</HTML>
<?php
}
/*--- close_page() ------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	OPEN_TABLE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function open_table($class = NULL, $caption = NULL)
{
	echo "<P>\n";
	echo "<TABLE align=center" . ($class ? " class=$class" : "") . ">\n";
	if ($caption)
		echo "<CAPTION>$caption</CAPTION>";
}
/*--- open_table() ------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	CLOSE_TABLE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function close_table()
{
	echo "</TABLE>\n";
	echo "</P>\n";
}
/*--- close_table() -----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	NOTICE
	Output an important message in a conspicuous box.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function notice($msg)
{
?>
<P>
	<TABLE class=notice align=center>
		<TR>
			<TD><?=$msg?></TD>
		</TR>
	</TABLE>
</P>
<?php
	return (-1);
}
/*--- notice() ----------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	FATAL
	Output fatal error and exit.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function fatal($msg)
{
	notice($msg);
	close_page();
	exit;
}
function fatalSQL($msg) { fatal($msg . "<BR><DIV class=main>" . mysql_error() . "</DIV>"); }
/*--- fatal() -----------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SQLCOUNT
	Simple wrapper to return a numeric value from a query whose result contains only one row and
	column.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function sqlcount($query)
{
	$res = mysql_query($query) or fatalSQL("Error executing SQL count.");
	$row = mysql_fetch_row($res);
	return ($row[0]);
}
/*--- sqlcount() --------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	FIXFQDN
	Trims the specified name, makes sure it has a dot at the end.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function fixfqdn($name)
{
	$name = trim($name);
	$len = strlen($name);
	if ($len && $name[($len-1)] != '.')
		$name .= ".";
	return ($name);
}
/*--- fixfqdn() ---------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	DURATION
	Output the human-friendly duration of time represented by a specified number of seconds.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function duration($seconds)
{
	$weeks = floor($seconds / 604800); $seconds -= ($weeks * 604800);
	$days = floor($seconds / 86400); $seconds -= ($days * 86400);
	$hours = floor($seconds / 3600); $seconds -= ($hours * 3600);
	$minutes = floor($seconds / 60); $seconds -= ($minutes * 60);
	if ($weeks) $rv .= "$weeks" . " week" . S($weeks);
	if ($days) $rv .= (strlen($rv) ? ", " : "") . "$days" . " day" . S($days);
	if ($hours) $rv .= (strlen($rv) ? ", " : "") . "$hours" . " hour" . S($hours);
	if ($minutes) $rv .= (strlen($rv) ? ", " : "") . "$minutes" . " minute" . S($minutes);
	if ($seconds || !strlen($rv))
		$rv .= (strlen($rv) ? ", " : "") . "$seconds" . "second" . S($seconds);
	return ($rv);
}
/*--- duration() --------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SERIAL_GUESS
	Attempt to guess a good value for incrementing serial number.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function serial_guess($serial)
{
	$now = time();
	$low = $now - (31449600 * 2);							/* Time 2 years ago */
	$high = $now + (31449600 * 1);						/* Time 1 year hence */
	$curyear = (int)strftime("%Y", $now);				/* The current year */
	$timestamp = strftime("%Y%m%d", $now);				/* The current timestamp */

	/* If the first four characters look like a year, suggest a YYYYMMDD type format */
	$first = substr($serial, 0, 4);
	if ($first >= ($curyear-10) && $first <= ($curyear+1))
	{
		$rv = substr($timestamp, 0, strlen($serial));
		return ("current " . substr("YYYYMMDD", 0, strlen($serial)) . " is $rv");
	}

	/* If it looks like a Unix timestamp, return the current timestamp */
	if ($serial >= $low && $serial <= $high)
	{
		if ($now == $serial) $now++;
		return ("current Unix timestamp is $now");
	}

	/* If the current serial is a number that's less than the unix time 10 years ago, assume
		the serial is a simple number being incremented */
	if ($serial < $low)
		return ("suggested update value: " . ($serial+1));

	/* Otherwise return the "timestamp of choice" - YYYYMMDD */
	return ("current YYYYMMDD is $timestamp");
}
/*--- serial_guess() ----------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	LOAD_SOA
	Attempts to load a SOA record for the specified query.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function load_soa($origin)
{
	global $host;		/* Any extraneous hostname found prior to the origin */

	$origin = fixfqdn($origin);
	for ($n = 0; $n < strlen($origin); $n++)
		if ($n == 0 || $origin[$n] == '.')
		{
			$part = substr($origin, ($n == 0 ? $n : ($n + 1)));
			if (strlen($part))
			{
				$res = mysql_query("SELECT * FROM soa WHERE origin='".mysql_escape_string($part)."'")
					or fatalSQL("Error locating SOA for &quot;$part&quot;.");
				if ($soa = mysql_fetch_array($res))
				{
					if (strlen($part) != strlen($origin))
					{
						$host = substr($origin, 0, strlen($origin) - strlen($part));
						if ($host[strlen($host)-1] == '.')
							$host = substr($host, 0, strlen($host)-1);
					}
					return ($soa);
				}
			}
		}
	return 0;
}
/*--- load_soa() --------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SOA_FORM
	Outputs the "edit soa" form.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function soa_form($soa)
{
	global $PHP_SELF, $query;

?>
<FORM method=POST action="<?=$PHP_SELF?>">
<INPUT type=hidden name=action value="soaupdate">
<INPUT type=hidden name=query value="<?=$query?>">
<INPUT type=hidden name=soa value="<?=$soa[id]?>">
<TABLE align=center class=soa>
	<TR>
		<TD colspan=3>
			<TABLE><TR>
				<TD><SPAN title="zone id <?=$soa[id]?>"><B><?=$soa[origin]?></B></SPAN></TD>
				<TD>
					<INPUT type=text name=ttl value="<?=$soa[ttl]?>" size=7
					 title="The TTL for this SOA record.">
				</TD>
				<TD>IN SOA</TD>
				<TD>
					<INPUT type=text name=ns value="<?=$soa[ns]?>" size=30 maxlength=255
					 title="The authoritative nameserver for this zone.">
				</TD>
				<TD>
					<INPUT type=text name=mbox value="<?=$soa[mbox]?>" size=30 maxlength=255
					 title="The administrative mailbox for this zone."> (
				</TD>
			</TR></TABLE>
		</TD>
	</TR>
	<TR>
		<TD class=leftindent>
			<INPUT type=text name=serial value="<?=$soa[serial]?>" size=15
			 title="The serial number for this zone.">
		</TD>
		<TD colspan=2>; Serial (<?=serial_guess($soa[serial])?>)</TD>
	</TR>
	<TR>
		<TD class=leftindent>
			<INPUT type=text name=refresh value="<?=$soa[refresh]?>" size=7
			 title="SOA refresh time, in seconds.">
		</TD>
		<TD colspan=2>; Refresh (currently <?=duration($soa[refresh])?>)</TD>
	</TR>
	<TR>
		<TD class=leftindent>
			<INPUT type=text name=retry value="<?=$soa[retry]?>" size=7
			 title="SOA retry time, in seconds.">
		</TD>
		<TD colspan=2>; Retry (currently <?=duration($soa[retry])?>)</TD>
	</TR>
	<TR>
		<TD class=leftindent>
			<INPUT type=text name=expire value="<?=$soa[expire]?>" size=7
			 title="SOA expire time, in seconds.">
		</TD>
		<TD colspan=2>; Expire (currently <?=duration($soa[expire])?>)</TD>
	</TR>
	<TR>
		<TD class=leftindent>
			<INPUT type=text name=minimum value="<?=$soa[minimum]?>" size=7
			 title="Minimum TTL for records within zone, in seconds.">
			)
		</TD>
		<TD>; Minimum TTL for zone (currently <?=duration($soa[minimum])?>)</TD>
		<TD align=right><INPUT type=submit value="Update"></TD>
	</TR>
</TABLE>
</FORM>
<?php
}
/*--- soa_form() --------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	RRFORM
	Outputs the one-row "form" for a resource record.
	If $rr is not-NULL, output a form with Update and Delete buttons.
	If $rr is NULL, output a form with empty fields and an "add" button.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function rrform($soa, $rr = NULL, $force_name = NULL)
{
	global $PHP_SELF, $query;

	$action = ($rr ? "rrupdate" : "rrinsert");

?>
<FORM method=POST action="<?=$PHP_SELF?>">
<INPUT type=hidden name=query value="<?=$query?>">
<INPUT type=hidden name=action value="<?=$action?>">
<INPUT type=hidden name=soa value="<?=$soa[id]?>">
<INPUT type=hidden name=rr value="<?=$rr[id]?>">
	<TR>
		<TD class="<?=$action?>">
<?php
	if ($rr)
	{
		echo "<SPAN title=\"rr $rr[id] \nzone $rr[zone]\">";
		echo (strlen($rr[name]) ? $rr[name] : "<B>$soa[origin]</B>");
		echo "</SPAN>";
		echo "<INPUT type=hidden name=name value=\"$rr[name]\">";
	}
	else if ($force_name)
	{
		echo $force_name;
		echo "<INPUT type=hidden name=name value=\"$rr[name]\">";
	}
	else
		echo "<INPUT type=text name=name size=30 title=\"The name for this resource record.\">";
?>
		</TD>
		<TD class="<?=$action?>">
			<INPUT type=text name=ttl value="<?=($rr ? $rr[ttl] : $soa[minimum])?>" size=7
			 title="The TTL for this resource record.">
		</TD>
		<TD class="<?=$action?>">IN</TD>
		<TD class="<?=$action?>">
<?php
	echo "<SELECT name=type size=1>";
	foreach (array("A","AAAA","CNAME","MX","NS","TXT") as $type)
		echo "<OPTION" . (!strcasecmp($rr[type], $type) ? " selected" : "") . ">$type";
	echo "</SELECT>";
?>
		</TD>
		<TD class="<?=$action?>">
			<INPUT type=text name=aux value="<?=($rr[aux] ? $rr[aux] : "")?>" size=3
			 title="Auxillary value for this resource record.">
		</TD>
		<TD class="<?=$action?>">
			<INPUT type=text name=data value="<?=$rr[data]?>" size=30 maxlength=255
			 title="Data for this resource record.">
		</TD>
<?php
	if ($rr)				/* Output "Update" and "Delete" buttons */
	{
?>
		<TD class="<?=$action?>"><INPUT type=submit name="rraction" value="Update"></TD>
		<TD class="<?=$action?>"><INPUT type=submit name="rraction" value="Delete"></TD>
<?php
	}
	else					/* $rr is NULL; output a "Create" button */
	{
?>
		<TD class="<?=$action?>" colspan=2><INPUT type=submit value="Create new RR"></TD>
<?php
	}
?>
	</TR>
</FORM>
<?php
}
/*--- rrform() ----------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	TOP_LEVEL_RR_EDIT_FORM
	Outputs the form containing primary zone data (i.e. rr's with blank names or `*').
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function top_level_rr_edit_form($soa)
{
	open_table("rr");
	$q = "SELECT * FROM rr WHERE zone=$soa[id] AND name='' ORDER BY name,type";
	$res = mysql_query($q)
		or fatalSQL("Error loading primary resource records for &quot;$soa[origin]&quot; zone.");
	while ($rr = mysql_fetch_array($res))
		rrform($soa, $rr);
	rrform($soa);
	close_table();
}
/*--- top_level_rr_edit_form() ------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	ZONE_RR_EDIT_FORM
	Outputs a list of resource records to edit.  If $name is provided, only that resource
	record will be shown.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function zone_rr_edit_form($soa)
{
	open_table("rr", "Resource records");
	$q = "SELECT * FROM rr WHERE zone=$soa[id] AND name != '' ORDER BY name,type";
	$res = mysql_query($q)
		or fatalSQL("Error loading primary resource records for &quot;$soa[origin]&quot; zone.");
	while ($rr = mysql_fetch_array($res))
		rrform($soa, $rr);
	rrform($soa);
	close_table();
}
/*--- zone_rr_edit_form() -----------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SHOW_FORM
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function show_form($query)
{
	global $host;

	if (!strlen($query))
		return;
	$soa = load_soa($query) or fatal("Unable to find any records matching your query.");
	soa_form($soa);
	top_level_rr_edit_form($soa);
	zone_rr_edit_form($soa);
}
/*--- show_form() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	CHECK_SOA_FORMDATA
	Returns 0 if everything is OK, -1 if not.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function check_soa_formdata()
{
	global $HTTP_POST_VARS;
	global $ttl_min, $refresh_min, $retry_min, $expire_min;

	/* Load SOA record for record being updated */
	$res = mysql_query("SELECT * FROM soa WHERE id=".(int)($HTTP_POST_VARS[soa]))
		or fatalSQL("Error loading soa {$HTTP_POST_VARS[soa]}.");
	$soa = mysql_fetch_array($res) or fatal("Unable to find soa {$HTTP_POST_VARS[soa]}.");
	$soa[minimum] = (int)$HTTP_POST_VARS[minimum];

	$fail = "<BR>SOA record not updated.";

	foreach ($HTTP_POST_VARS as $n => $v)
		$HTTP_POST_VARS[$n] = trim($v);

	foreach ($HTTP_POST_VARS as $n => $v)
	switch ($n)
	{
		case "ns":
			$v = $HTTP_POST_VARS[$n] = fixfqdn($v);
			if (!strlen($v)) return notice("Authoritative nameserver field empty.".$fail);
			if (strlen($v) > 255) return notice("Authoritative nameserver field too long.".$fail);
			break;

		case "mbox":
			$v = $HTTP_POST_VARS[$n] = fixfqdn($v);
			if (!strlen($v)) return notice("Administrative mailbox field empty.".$fail);
			if (strlen($v) > 255) return notice("Administrative mailbox field too long.".$fail);
			break;

		case "ttl":
			if ($v < $ttl_min)
				return notice("TTL unreasonably short.<BR>".
						 "The minimum allowable value is $ttl_min (".duration($ttl_min).").".$fail);
			if ($v < $soa[minimum])
			{
				$HTTP_POST_VARS[ttl] = $soa[minimum];
				notice("TTL raised to {$soa[minimum]} (".duration($soa[minimum]).") ".
						 "to comply with the minimum TTL for this zone.");
			}
			break;

		case "serial":
			if (!strlen($v))
				return notice("Serial field empty.".$fail);
			break;

		case "refresh":
			if ($v < $refresh_min)
				return notice("Refresh time unreasonably short.<BR>".
								  "The minimum allowable value is $refresh_min ".
								  "(".duration($refresh_min).").".$fail);
			break;

		case "retry":
			if ($v < $retry_min)
				return notice("Retry time unreasonably short.<BR>".
								  "The minimum allowable value is $retry_min ".
								  "(".duration($retry_min).").".$fail);
			break;

		case "expire":
			if ($v < $expire_min)
				return notice("Expiration time unreasonably short.<BR>".
								  "The minimum allowable value is $expire_min ".
								  "(".duration($expire_min).").".$fail);
			break;

		case "minimum":
			if ($v < $minimum_min)
				return notice("Minimum TTL unreasonably short.<BR>".
								  "The minimum allowable value is $ttl_min ".
								  "(".duration($ttl_min).").".$fail);
			break;
	}
	return (0);
}
/*--- check_soa_formdata() ----------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	SOA_UPDATE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function soaupdate()
{
	global $HTTP_POST_VARS;

	if (check_soa_formdata() == -1)
		return;

	$q  = "UPDATE soa SET ";
	$q .= "ns='" . esc($HTTP_POST_VARS["ns"]) . "'";
	$q .= ",mbox='" . esc($HTTP_POST_VARS["mbox"]) . "'";
	$q .= ",serial=" . (int)($HTTP_POST_VARS["serial"]);
	$q .= ",refresh=" . (int)($HTTP_POST_VARS["refresh"]);
	$q .= ",retry=" . (int)($HTTP_POST_VARS["retry"]);
	$q .= ",expire=" . (int)($HTTP_POST_VARS["expire"]);
	$q .= ",minimum=" . (int)($HTTP_POST_VARS["minimum"]);
	$q .= ",ttl=" . (int)($HTTP_POST_VARS["ttl"]);
	$q .= " WHERE id=" . (int)($HTTP_POST_VARS["soa"]);

	mysql_query($q) or fatalSQL("Error updating SOA.");
}
/*--- soaupdate() ------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	RR_DELETE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function rr_delete()
{
	global $HTTP_POST_VARS;

	$q  = "DELETE FROM rr WHERE id=" . (int)$HTTP_POST_VARS[rr];

	mysql_query($q) or fatalSQL("Error deleting resource record.");
}
/*--- rr_delete() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	CHECK_RR_FORMDATA
	Returns 0 if everything is OK, -1 if not.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function check_rr_formdata($desc = "updated")
{
	global $HTTP_POST_VARS;
	global $ttl_min;

	/* Load SOA record for record being updated */
	$res = mysql_query("SELECT * FROM soa WHERE id=".(int)($HTTP_POST_VARS[soa]))
		or fatalSQL("Error loading soa {$HTTP_POST_VARS[soa]}.");
	$soa = mysql_fetch_array($res) or fatal("Unable to find soa {$HTTP_POST_VARS[soa]}.");

	$fail = "<BR>Resource record not $desc.";

	foreach ($HTTP_POST_VARS as $n => $v)
		$HTTP_POST_VARS[$n] = trim($v);

	foreach ($HTTP_POST_VARS as $n => $v)
	switch ($n)
	{
		case "name":
			if ($v == $soa[origin] || "$v." == $soa[origin])
				$v = $HTTP_POST_VARS[name] = "";
			while ($v[strlen($v)-1] == '.')
				$v = $HTTP_POST_VARS[name] = substr($v, 0, strlen($v)-1);
			if (strlen($v) > 64) return notice("Name field too long.".$fail);
			break;

		case "ttl":
			if ($v < $soa[minimum])
			{
				$v = $HTTP_POST_VARS[ttl] = $soa[minimum];
				notice("TTL raised to {$soa[minimum]} (".duration($soa[minimum]).") ".
						 "to comply with the minimum TTL for this zone.");
			}
			if ($v < $ttl_min)
				return notice("TTL unreasonably short.<BR>".
						 "The minimum allowable value is $ttl_min (".duration($ttl_min).").".$fail);
			break;

		case "type":		/* Do special processing on `data' for certain types */
			switch ($v)
			{
				case "A":
					/* XXX: Validate IPv4 address */
					$HTTP_POST_VARS[aux] = 0;
					break;

				case "AAAA":
					/* XXX: Validate IPv6 address */
					$HTTP_POST_VARS[aux] = 0;
					break;

				case "CNAME":
					$HTTP_POST_VARS[data] = fixfqdn($HTTP_POST_VARS[data]);
					$HTTP_POST_VARS[aux] = 0;
					break;

				case "MX":
					$HTTP_POST_VARS[data] = fixfqdn($HTTP_POST_VARS[data]);
					if ($HTTP_POST_VARS[aux] <= 0)
						$HTTP_POST_VARS[aux] = 1;
					break;

				case "NS":
					$HTTP_POST_VARS[data] = fixfqdn($HTTP_POST_VARS[data]);
					$HTTP_POST_VARS[aux] = 0;
					break;

				default:		/* "aux" is only used with MX records */
					$HTTP_POST_VARS[aux] = 0;
					break;
			}
			break;

		case "data":
			if (!strlen($v)) return notice("Data field empty.".$fail);
			if (strlen($v) > 255) return notice("Data field too long.".$fail);
			break;
	}
	return (0);
}
/*--- check_rr_formdata() -----------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	RR_UPDATE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function rrupdate()
{
	global $HTTP_POST_VARS;

	if (check_rr_formdata("updated") == -1)
		return;

	$q  = "UPDATE rr SET ";
	$q .= "name='" . esc($HTTP_POST_VARS["name"]) . "'";
	$q .= ",type='" . esc($HTTP_POST_VARS["type"]) . "'";
	$q .= ",data='" . esc($HTTP_POST_VARS["data"]) . "'";
	$q .= ",aux=" . (int)($HTTP_POST_VARS["aux"]);
	$q .= ",ttl=" . (int)($HTTP_POST_VARS["ttl"]);
	$q .= " WHERE id=" . (int)($HTTP_POST_VARS["rr"]);

	mysql_query($q) or fatalSQL("Error updating resource record.");
}
/*--- rrupdate() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	RR_INSERT
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
function rrinsert()
{
	global $HTTP_POST_VARS;

	if (check_rr_formdata("created") == -1)
		return;

	$q  = "INSERT INTO rr SET ";
	$q .= "zone=" . (int)($HTTP_POST_VARS["soa"]);
	$q .= ",name='" . esc($HTTP_POST_VARS["name"]) . "'";
	$q .= ",type='" . esc($HTTP_POST_VARS["type"]) . "'";
	$q .= ",data='" . esc($HTTP_POST_VARS["data"]) . "'";
	$q .= ",aux=" . (int)($HTTP_POST_VARS["aux"]);
	$q .= ",ttl=" . (int)($HTTP_POST_VARS["ttl"]);

	mysql_query($q) or fatalSQL("Error creating resource record.");
}
/*--- rrinsert() -------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	MAIN
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
open_page();

mysql_connect($dbhost, $dbuser, $dbpass) or fatalSQL("Unable to connect to database.");
mysql_select_db($dbname) or fatalSQL("Unable to select database.");

switch ($action)
{
	case "soaupdate":
		soaupdate();
		break;

	case "rrupdate":
		if ($rraction == "Delete")
			rr_delete();
		else if ($rraction == "Update")
			rrupdate();
		break;

	case "rrinsert":
		rrinsert();
		break;

	default:
		if ($action)
			notice("Unknown action: &quot;$action&quot;");
		break;
}

show_form($query);
close_page();

/*-----------------------------------------------------------------------------------------------*/

/* vi:set ts=3: */ ?>
